package hirt;

import java.nio.ByteBuffer;
import java.util.Vector;

/**
 * Lane is derived from Item2D. However, it is considered a somewhat special
 * Item2D, in that it can "collide" with more volatile items like an automobile.
 * Lanes comprise the basic element of a road, including shoulders. Lanes have
 * direction (forward or backward); however, current code does not utilize this
 * attribute. But, it would be very useful in future development. Lanes have
 * speed limits (again, under utilized but possibly helpful). Lanes are usually
 * grouped together, having lane adjancency. Again, this property is under
 * utilized, but could be used to determine (in conjuction with the lane direction)
 * what style and color of lines should be drawn. For current ease of use,
 * lanes are either vertical or horizontal, stretching indefinitely for now.
 * @author puzzud
 */
public class Lane extends Item2D
{
    /**
     * Which way traffic should run on this lane (forward or backward).
     */
    private int direction;

    //Vector<Point> path;

    /**
     * Intended speed limit for this lane (usually shaired by adjacent lanes).
     */
    int speedLimit;

    /**
     * Lane adjanceny references. (null indicates non-adjancency).
     */
    Lane adjacentLaneLeft, adjacentLaneRight;

    /**
     * Lane sub types.
     */
    public static final String TYPE_VERTICAL    = ServerConstants.ITEM_TYPE_NAME[ServerConstants.VERTICAL_LANE];
    public static final String TYPE_HORIZONTAL  = ServerConstants.ITEM_TYPE_NAME[ServerConstants.HORIZONTAL_LANE];
    public static final String TYPE_VERTICAL_SHOULDER    = ServerConstants.ITEM_TYPE_NAME[ServerConstants.VERTICAL_SHOULDER];
    public static final String TYPE_HORIZONTAL_SHOULDER  = ServerConstants.ITEM_TYPE_NAME[ServerConstants.HORIZONTAL_SHOULDER];

    /**
     * Lane directions (obsolete, as orientation should suggest vector direction,
     * only needing a positive or negative value).
     */
    public static final int DIRECTION_UP    = -1;
    public static final int DIRECTION_DOWN  = 1;
    public static final int DIRECTION_LEFT  = -1;
    public static final int DIRECTION_RIGHT = 1;

    /**
     * Lane constructor that is tailored specifically to the type specified.
     * @param type specified sub type of this lane.
     */
    public Lane( String type )
    {
        super();
        setDirection( DIRECTION_UP );
        speedLimit = 1;
        setType( type );
        adjacentLaneLeft = null;
        adjacentLaneRight = null;
    }

    /**
     * Lane constructor that is tailored specifically to the type specified,
     * while also providing lane adjancency.
     * @param type specified sub type of this lane.
     * @param left adjacent lane to the left.
     * @param right adjacent lane to the right.
     */
    public Lane (String type, Lane left, Lane right)
    {
        this(type);
        this.adjacentLaneLeft = left;
        this.adjacentLaneRight = right;
    }

    /**
     * Builds an Item from a byte stream, presumably created by an item across the network
     * this item should be identical to that one
     * @param bytes
     * @param items: Master Item List used to build the Item
     */
    public Lane(ByteBuffer bytes, Vector<Item> items)
    {
        fromBytes(bytes,items);
    }

    /**
     * Builds an Item from a save string, presumably created by an item when saving to a file
     * this item should be identical to that one
     * @param saveString
     * @param items: Master Item List used to build the Item
     */
    public Lane( String text, Vector<Item> items )
    {
        fromSaveString(text, items);
    }

    /**
     * Constructor for lane that sets the position of this lane, as well
     * as the sub type.
     * @param type specified sub type of this lane.
     * @param x horizontal coordinate of this lane.
     * @param y vertical coordinate of this lane.
     */
    public Lane( String type, int x, int y )
    {
        super();
        setDirection( DIRECTION_UP );
        speedLimit = 1;
        setType( type );
        setPosition( x, y );
    }

    /**
     * Set left lane adjancency.
     * @param left adjacent lane to the left.
     */
    public void setLeft(Lane left)
    {
        this.adjacentLaneLeft = left;
    }

    /**
     * Set right lane adjancency.
     * @param right adjacent lane to the right.
     */
    public void setRight(Lane right)
    {
        this.adjacentLaneRight = right;
    }

    public int getDirection()
    {
        return( direction );
    }

    public void setDirection( int direction )
    {
        this.direction = direction;
    }
/*
    public Vector<Point> getPath()
    {
        return( path );
    }
*/
    /*
    public void setPath( Vector<Point> path )
    {
        this.path = path;
    }
     */

    public int getSpeedLimit()
    {
        return( speedLimit );
    }

    public void setSpeedLimit( int speedLimit )
    {
        this.speedLimit = speedLimit;
    }

    /**
     * Returns a ByteBuffer representation of this Item
     * Used to send items over the network
     * @return ByteBuffer
     */
    @Override
    public ByteBuffer toByte()
    {
        ByteBuffer buf = super.toByte();
        buf.putInt(direction);
        buf.putInt(speedLimit);
        buf.putInt(ByteChanger.itemToByte(adjacentLaneLeft));
        buf.putInt(ByteChanger.itemToByte(adjacentLaneRight));
        return buf;
    }

    /**
     * Returns a String representation of this Item
     * Used to save this item to a file
     * @return Save String
     */
    @Override
    public String toSaveString()
    {
        String text = super.toSaveString();
        text += direction + "\t";
        text += speedLimit + "\t";
        text += ByteChanger.itemToByte(adjacentLaneLeft) + "\t";
        text += ByteChanger.itemToByte(adjacentLaneRight) + "\t";
        return text;
    }


    /**
     * Builds an Item from a byte stream, presumably created by an item across the network
     * this item should be identical to that one
     * @param bytes
     * @param items: Master Item List used to build the action
     * @return what's left of the parem bytes after this method is completes
     */
    @Override
    protected ByteBuffer fromBytes(ByteBuffer bytes, Vector<Item> items)
    {
        bytes = super.fromBytes(bytes, items);
        direction = bytes.getInt(0);
        speedLimit = bytes.getInt(4);
        adjacentLaneLeft = (Lane)ByteChanger.getItem(bytes, items, 8);
        adjacentLaneRight = (Lane)ByteChanger.getItem(bytes, items, 12);
        try {
            bytes = ByteChanger.truncate(bytes, 16);
        } catch (Exception ex) {

        }
        return bytes;
    }

    /**
     * Builds an Item from a save string, presumably read from a save
     * this item should be identical to the one saved in the file
     * @param save string
     * @param items: Master Item List used to build the action
     * @return what's left of the parem SaveString after this methods completes
     */
    @Override
    protected String fromSaveString(String text, Vector<Item> items)
    {
        text = super.fromSaveString(text, items);
        String substring = ByteChanger.getNextValue(text);
        direction = Integer.parseInt(substring);

        text = ByteChanger.incrementString(text);
        substring = ByteChanger.getNextValue(text);
        speedLimit = Integer.parseInt(substring);

        text = ByteChanger.incrementString(text);
        substring = ByteChanger.getNextValue(text);
        adjacentLaneLeft = (Lane)ByteChanger.getItem(substring, items);

        text = ByteChanger.incrementString(text);
        substring = ByteChanger.getNextValue(text);
        adjacentLaneRight = (Lane)ByteChanger.getItem(substring, items);

        text = ByteChanger.incrementString(text);
        return text;
    }

    /**
     * Cheap way of fitting a theoretically infinitely stretching straight lane
     * into a specified bounding area.
     * @param width horizontal dimension of the bounding area.
     * @param height vertical dimension of the bounding area.
     */
    void fit( int width, int height )
    {
        if( type.equals( TYPE_VERTICAL ) )
        {
            setYPosition( 0 );
            setWidth( this.width );
            setHeight( height );
        }
        else
        if( type.equals( TYPE_VERTICAL_SHOULDER ) )
        {
            setYPosition( 0 );
            setWidth( this.width );
            setHeight( height );
        }
        else
        if( type.equals( TYPE_HORIZONTAL ) )
        {
            setXPosition( 0 );
            setWidth( width );
            setHeight( this.height );
        }
        else
        if( type.equals( TYPE_HORIZONTAL_SHOULDER ) )
        {
            setXPosition( 0 );
            setWidth( width );
            setHeight( this.height );
        }
    }

    /**
     * Set the type of lane, specifically tailored to the different sub types of
     * lane. Set the dimensions accordingly.
     * @param type specified sub type of lane.
     */
    @Override
    public void setType( String type )
    {
        super.setType( type );

        if( type.equals( TYPE_VERTICAL ) )
        {
            setWidth( ServerConstants.ITEM2D_DIMENSIONS[ServerConstants.VERTICAL_LANE].x );
            setHeight( ServerConstants.ITEM2D_DIMENSIONS[ServerConstants.VERTICAL_LANE].y );
        }
        else
        if( type.equals( TYPE_VERTICAL_SHOULDER ) )
        {
            setWidth( ServerConstants.ITEM2D_DIMENSIONS[ServerConstants.VERTICAL_SHOULDER].x );
            setHeight( ServerConstants.ITEM2D_DIMENSIONS[ServerConstants.VERTICAL_SHOULDER].y );
        }
        else
        if( type.equals( TYPE_HORIZONTAL ) )
        {
            setWidth( ServerConstants.ITEM2D_DIMENSIONS[ServerConstants.HORIZONTAL_LANE].x );
            setHeight( ServerConstants.ITEM2D_DIMENSIONS[ServerConstants.HORIZONTAL_LANE].y );
        }
        else
        if( type.equals( TYPE_HORIZONTAL_SHOULDER ) )
        {
            setWidth( ServerConstants.ITEM2D_DIMENSIONS[ServerConstants.HORIZONTAL_SHOULDER].x );
            setHeight( ServerConstants.ITEM2D_DIMENSIONS[ServerConstants.HORIZONTAL_SHOULDER].y );
        }
    }
}
